package net

import (
	"encoding/json"
	"log"
	"sync"
	"tk_server/utils"

	"github.com/forgoer/openssl"
	"github.com/gorilla/websocket"
)

// websocket服务
type wsServer struct {
	wsConn       *websocket.Conn
	router       *Router
	outChan      chan *WsMsgRsp
	Seq          int64
	property     map[string]interface{}
	propertyLock sync.RWMutex
}

func NewWsServer(wsConn *websocket.Conn) *wsServer {
	return &wsServer{
		wsConn:   wsConn,
		outChan:  make(chan *WsMsgRsp, 1000),
		property: make(map[string]interface{}),
		Seq:      0,
	}
}

func (w *wsServer) Router(router *Router) {
	w.router = router
}

func (w *wsServer) SetProperty(key string, value interface{}) {
	w.propertyLock.Lock()
	defer w.propertyLock.Unlock()
	w.property[key] = value
}

func (w *wsServer) GetProperty(key string) (interface{}, error) {
	w.propertyLock.RLock()
	defer w.propertyLock.RUnlock()
	return w.property[key], nil
}

func (w *wsServer) RemoveProperty(key string) {
	w.propertyLock.Lock()
	defer w.propertyLock.Unlock()
	delete(w.property, key)
}

func (w *wsServer) Addr() string {
	return w.wsConn.RemoteAddr().String()
}

func (w *wsServer) Push(name string, data interface{}) {
	rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: 0}}
	w.outChan <- rsp
}

// 通道一旦建立，收发消息就要一直监听才行
func (w *wsServer) Start() {
	// 启动读写数据的逻辑
	go w.readMsgLoop()
	go w.writeMsgLoop()
}

func (w *wsServer) readMsgLoop() {
	// 检查是否关闭连接
	defer func() {
		if err := recover(); err != nil {
			log.Fatal(err)
			w.Close()
		}
	}()

	// 先读到客户端消息，然后进行处理，再回消息
	for {
		_, data, err := w.wsConn.ReadMessage()
		if err != nil {
			log.Println("收消息出现错误：", err)
			break
		}

		// 收到消息，解析消息
		// 前端发的是json格式的

		// 1. 解压data
		data, err = utils.UnZip(data)
		if err != nil {
			log.Println("解压数据出错，非法格式", err)
			continue
		}

		// 2. 前端的消息是加密发的，需要解密(和业务有关系)
		secretKey, err := w.GetProperty("secretKey")

		if err == nil {
			// 找到加密密钥即有加密的话
			// 有加密
			key := secretKey.(string)
			// 客户端传过来的数据是加密的 需要解密
			d, err := utils.AesCBCDecrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING)
			if err != nil {
				log.Println("数据格式有误，解密失败:", err)
				// 出错后 发起握手
				// w.Handshake()
			} else {
				data = d
			}
		}
		// 3. data转为body, 即反序列化
		body := &ReqBody{}
		err = json.Unmarshal(data, body)
		if err != nil {
			log.Println("反序列化数据有错误", err)
			continue
		} else {
			// 获取到前端传递的数据了, 要拿上这些数据, 去具体的业务处理
			// rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: 0}}
			// w.outChan <- rsp
			req := &WsMsgReq{Conn: w, Body: body}
			rsp := &WsMsgRsp{Body: &RspBody{Name: body.Name, Seq: req.Body.Seq}}
			w.router.Run(req, rsp)
			w.outChan <- rsp
		}
	}
	w.Close()
}

func (w *wsServer) Write(rsp *WsMsgRsp) {
	data, err := json.Marshal(rsp)
	if err != nil {
		log.Println(err)
		return
	}

	secretKey, err := w.GetProperty("secretKey")
	if err == nil {
		// 有加密
		key := secretKey.(string)
		// 数据加密
		data, _ = utils.AesCBCEncrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING)

	}

	//压缩
	if data, err := utils.Zip(data); err == nil {
		w.wsConn.WriteMessage(websocket.BinaryMessage, data)
	}
}

func (w *wsServer) writeMsgLoop() {
	for {
		select {
		case msg := <-w.outChan:
			w.Write(msg)

		}
	}
}

func (w *wsServer) Close() {
	_ = w.wsConn.Close()
}
